# Check the first few rows of the numeric columns
numeric_cols <- c("ERA","WHIP","K.9","BB","H","FPS.","IP")
head(GPE_PITCH_FILTERED[numeric_cols])
## ERA WHIP K.9 BB H FPS. IP
## 1 3.00 1.27 6.90 15 23 55.80% 30.0
## 2 9.38 1.89 3.41 30 30 41.30% 31.2
## 3 6.93 1.54 9.49 13 25 64.90% 24.2
## 4 6.49 1.75 5.81 14 32 57.80% 26.1
## 6 3.72 1.24 8.38 9 15 50.60% 19.1
## 7 4.26 1.37 5.21 15 11 46.40% 19.0
# Remove any non-numeric characters from FPS. (like % signs) and convert to numeric
GPE_PITCH_FILTERED$FPS. <- as.numeric(gsub("%","",GPE_PITCH_FILTERED$FPS.))
# Ensure other columns are numeric
for(col in numeric_cols[-6]) { # exclude FPS. since we handled it
GPE_PITCH_FILTERED[[col]] <- as.numeric(GPE_PITCH_FILTERED[[col]])
}
# Define weights including BAA
weights_pitching <- c(
ERA = -0.30,
WHIP = -0.32,
K.9 = 0.08,
BB = -0.05,
H = -0.05,
FPS. = 0.05,
IP = 0.10,
BAA = -0.1 # Added BAA, higher is worse
)
# Compute PitchingScore
# Compute PitchingScore correctly
GPE_PITCH_FILTERED$PitchingScore <-
GPE_PITCH_FILTERED$ERA * weights_pitching["ERA"] +
GPE_PITCH_FILTERED$WHIP * weights_pitching["WHIP"] +
GPE_PITCH_FILTERED$K.9 * weights_pitching["K.9"] +
GPE_PITCH_FILTERED$BB * weights_pitching["BB"] +
GPE_PITCH_FILTERED$H * weights_pitching["H"] +
GPE_PITCH_FILTERED$FPS. * weights_pitching["FPS."] +
GPE_PITCH_FILTERED$IP * weights_pitching["IP"] +
GPE_PITCH_FILTERED$BAA * weights_pitching["BAA"]
# Check the result
print(GPE_PITCH_FILTERED[, c("PLAYER", "PitchingScore", "IP")])
## PLAYER PitchingScore IP
## 1 Max Arlich 3.1143 30.0
## 2 Lorenzo Atwell -0.9875 31.2
## 3 Payton Barton 1.9261 24.2
## 4 Easton Bobb 1.1270 26.1
## 6 Andres Castro 2.3759 19.1
## 7 Dylan Dickert 1.6018 19.0
## 8 Zach Diver 0.3470 32.0
## 10 Kenneth Fistler 2.7700 45.2
## 12 Josh Glaser 3.2854 19.2
## 14 Cohen Gomez 3.9848 48.2
## 15 Miller Green 2.8676 16.1
## 17 Bridger Hamilton -0.5658 21.2
## 18 Dawson Hargrove 5.1133 25.1
## 20 Jace Kirby 2.7684 16.0
## 23 Connor Lovin 0.5329 18.2
## 26 Austin Mattingly 1.3367 25.2
## 27 Walker Retz 3.4122 61.2
## 31 Austin Steeves 2.2335 23.0
## 32 Nathan Vela 1.6271 18.1
## 34 Anthony Andrews 2.5045 22.0
## 43 Ian Fisher 1.9622 16.2
## 44 Tanner Foertsch 3.3040 30.1
## 47 Carter Giesen 1.5653 19.2
## 51 Danny Hesse 1.8033 34.0
## 53 Matt Juza 0.2766 21.0
## 54 Jackson Kendall 2.4843 38.0
## 57 Owen Marsolek 0.9859 22.0
## 58 Chas Melvin IV 1.0373 19.1
## 59 Maddox Meyer 3.2366 23.2
## 60 Simon Murray 0.5467 20.1
## 63 James Rheaume -0.1304 18.1
## 65 Evan Rolison 2.7532 23.2
## 67 Jackson Smith 2.1145 38.2
## 68 Nick Terhaar 3.2994 31.2
## 69 Parker Thomas 3.1450 22.0
## 71 Nate Vidlak 3.9834 20.0
## 72 Sean Waits 3.3589 23.1
## 74 Collin Berry 0.6657 17.0
## 75 Parker Burgess 1.2620 16.1
## 77 Jimmy Cerha 0.1173 23.1
## 78 Makaio Cisneros 3.3774 26.0
## 79 Grant Faris -2.3774 30.2
## 80 Ethan Froud 0.9537 37.2
## 82 Braden Gluth 3.0303 34.0
## 88 Will Humphrey 2.7383 25.0
## 89 Jackson Irwin 0.7082 44.1
## 90 Cameron Johnson 1.4207 24.1
## 93 John McDonald 0.0326 30.0
## 96 Ethan Minaker 0.8241 29.0
## 98 Rylan Newman 1.9704 21.1
## 102 Jabe Schlehuber 1.2128 17.0
## 104 William Spang -0.3880 20.0
## 105 Tyler Talbert 1.4971 41.2
## 108 Carter Wall 2.4360 23.1
## 110 Cristien Banda 1.4501 38.0
## 111 Mason Beltrand 2.9062 32.2
## 112 Troy Benko 1.0111 23.1
## 113 Austin Berggren 2.3613 24.2
## 114 Matthew Cornelius 0.2357 17.2
## 116 Myles Dismute 2.3630 19.1
## 118 Luke Elward 1.3420 16.0
## 119 Aaron England 2.4938 26.1
## 121 Tyler Gebb 2.0886 28.0
## 122 Jack Ghufran 2.1204 41.2
## 123 Mateo Gray 2.4242 28.2
## 124 Jake Jakubowski 1.3713 22.0
## 126 Bobby McDonough 2.7899 18.2
## 127 Ashton Michek 3.0614 31.1
## 128 Jace Miner -1.7604 19.1
## 130 Jack Mount 4.0089 16.0
## 132 Luispablo Navarro 3.5703 20.1
## 133 Brayden Olson 1.9858 17.1
## 136 Caden Richardson 3.1722 39.0
## 142 Beck Sullivan -0.7757 31.2
## 143 Kassius Thomas 2.0475 17.1
## 144 Beau Alazaus 3.3002 57.2
## 146 Nick Bauer -0.6177 30.0
## 150 Isaiah Brennan -0.8202 28.1
## 153 Julian Castro 0.8326 20.1
## 154 Marcus Champagne 0.4582 21.0
## 155 Harrison Cordeiro 0.1146 24.0
## 158 Jaren Ekkelboom 0.3614 15.2
## 159 Gaines Estridge 2.8563 17.0
## 160 Patrick Fernandez 1.2406 18.0
## 161 Christian Galindo 2.5509 18.0
## 163 Ryan Higgins 0.9288 23.0
## 165 Caden Klebba 2.1917 33.1
## 166 Brady Lejeune-Deacutis 2.9632 28.2
## 167 Manny Lopez -1.6795 20.0
## 168 Diego Luzardo 0.3662 15.1
## 169 Hayden Mullins 2.5034 32.0
## 173 AJ Rasmussen -0.7932 17.1
## 174 Ian Regal 2.4677 34.1
## 176 Zack Serup 4.9693 27.1
## 179 Jacob Tostado 1.2894 20.0
## 180 Harmon Zylstra 0.2192 18.0
## 181 Alex Alberico 0.1620 24.2
## 183 Nakni Anna -1.1693 18.1
## 184 Brady Baur 1.1479 31.0
## 185 Colton Blankstrom 0.9381 21.0
## 187 Logan Boenker 1.7230 30.0
## 188 Kole Bradley 2.4231 18.1
## 194 Aidan Elfering 3.8999 51.1
## 196 Riley Fuller 2.1433 28.0
## 197 Tyler Glowacki 3.2528 26.1
## 202 Brody Leyboldt 1.2429 21.2
## 203 Camden Lyke 0.7002 21.1
## 207 Chris Petersen 4.0352 29.2
## 208 Eli Pillsbury 2.0243 40.2
## 209 Kai Purdy-Burton 0.2162 30.2
## 210 Juan Reyes 1.7142 15.1
## 211 Brandon Rice 3.0149 43.1
## 212 Luke Riggs 0.1257 18.2
## 214 Parker Sweeney 1.9431 25.0
## 216 Gannon Wentz 2.7018 24.0
library(ggplot2)
# Remove rows with NA PitchingScore or IP
plot_data <- GPE_PITCH_FILTERED[!is.na(GPE_PITCH_FILTERED$PitchingScore) & !is.na(GPE_PITCH_FILTERED$IP), ]
# Scatterplot
ggplot(plot_data, aes(x = BF, y = PitchingScore, label = PLAYER)) +
geom_point(aes(color = PitchingScore), size = 3) + # points colored by score
geom_text(vjust = -0.5, hjust = 0.5, size = 3) + # player labels
scale_color_gradient(low = "red", high = "green") + # low scores red, high green
labs(title = "Pitching Score vs Batters Faced",
x = "Batters Faced (BF)",
y = "Pitching Score") +
theme_minimal()
mean(GPE_PITCH_FILTERED$PitchingScore, na.rm = TRUE)
## [1] 1.693849
#calculate z-scores
GPE_PITCH_FILTERED$PitchingScore_z <- scale(GPE_PITCH_FILTERED$PitchingScore, center = TRUE, scale = TRUE)
#z-scores vs BF
# Ensure PitchingScore is numeric
GPE_PITCH_FILTERED$PitchingScore <- as.numeric(GPE_PITCH_FILTERED$PitchingScore)
# Compute z-scores
GPE_PITCH_FILTERED$PitchingScore_z <- scale(GPE_PITCH_FILTERED$PitchingScore)
# Define performance tiers
quantiles <- quantile(GPE_PITCH_FILTERED$PitchingScore, probs = c(0, 1/3, 2/3, 1), na.rm = TRUE)
GPE_PITCH_FILTERED$Tier <- cut(
GPE_PITCH_FILTERED$PitchingScore,
breaks = quantiles,
labels = c("Bottom", "Middle", "Top"),
include.lowest = TRUE
)
# Assign colors
colors <- c("Bottom" = "red", "Middle" = "yellow", "Top" = "green")
# Scatterplot
plot(
GPE_PITCH_FILTERED$BF,
GPE_PITCH_FILTERED$PitchingScore_z,
xlab = "Batters Faced",
ylab = "Pitching Score (Z-Score)",
main = "Pitching Score Z-Score vs Batters Faced",
pch = 19,
col = colors[GPE_PITCH_FILTERED$Tier]
)
# Add player names
text(
GPE_PITCH_FILTERED$BF,
GPE_PITCH_FILTERED$PitchingScore_z,
labels = GPE_PITCH_FILTERED$PLAYER,
pos = 3, # position above points
cex = 0.7
)
# Optional: add legend
legend("topright", legend = names(colors), col = colors, pch = 19, title = "Performance Tier")
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
# Count number of pitchers per team in each tier
team_tier_counts <- GPE_PITCH_FILTERED %>%
group_by(TEAM, Tier) %>%
summarise(Count = n(), .groups = "drop")
# Teams with the most Top-tier pitchers
top_teams <- team_tier_counts %>%
filter(Tier == "Top") %>%
arrange(desc(Count))
# Teams with the most Bottom-tier pitchers
bottom_teams <- team_tier_counts %>%
filter(Tier == "Bottom") %>%
arrange(desc(Count))
# Print results
print("Teams with most Top-tier pitchers:")
## [1] "Teams with most Top-tier pitchers:"
print(top_teams)
## # A tibble: 6 × 3
## TEAM Tier Count
## <chr> <fct> <int>
## 1 DULUTH Top 9
## 2 EAU CLAIRE Top 8
## 3 LA CROSSE Top 7
## 4 ROCHESTER Top 6
## 5 WATERLOO Top 5
## 6 THUNDER BAY Top 3
print("Teams with most Bottom-tier pitchers:")
## [1] "Teams with most Bottom-tier pitchers:"
print(bottom_teams)
## # A tibble: 6 × 3
## TEAM Tier Count
## <chr> <fct> <int>
## 1 ROCHESTER Bottom 11
## 2 THUNDER BAY Bottom 8
## 3 WATERLOO Bottom 6
## 4 DULUTH Bottom 5
## 5 EAU CLAIRE Bottom 5
## 6 LA CROSSE Bottom 4
GPE_PITCH_FILTERED <- GPE_PITCH_FILTERED %>%
mutate(
DICE = 3.00 + ((13 * HR) + (3 * (BB + HB)) - (2 * K)) / IP
)
library(dplyr)
# Rank dataset by DICE (lower is better)
DICE_Ranked <- GPE_PITCH_FILTERED %>%
arrange(DICE) %>% # sort ascending (best DICE first)
mutate(DICE_Rank = rank(DICE, ties.method = "first")) %>%
select(DICE_Rank, PLAYER, TEAM, DICE)
# Print the ranked dataset
print(DICE_Ranked)
## DICE_Rank PLAYER TEAM DICE
## 1 1 Dawson Hargrove EAU CLAIRE 1.525896
## 2 2 Maddox Meyer DULUTH 1.663793
## 3 3 Zack Serup ROCHESTER 1.892989
## 4 4 Cohen Gomez EAU CLAIRE 1.921162
## 5 5 Diego Luzardo ROCHESTER 1.940397
## 6 6 Nate Vidlak DULUTH 2.050000
## 7 7 Aaron England LA CROSSE 2.195402
## 8 8 Miller Green EAU CLAIRE 2.254658
## 9 9 Chris Petersen WATERLOO 2.417808
## 10 10 Parker Thomas DULUTH 2.454545
## 11 11 Jake Jakubowski LA CROSSE 2.500000
## 12 12 Makaio Cisneros THUNDER BAY 2.538462
## 13 13 Tyler Gebb LA CROSSE 2.571429
## 14 14 Mateo Gray LA CROSSE 2.751773
## 15 15 Tanner Foertsch DULUTH 2.800664
## 16 16 Luispablo Navarro LA CROSSE 2.800995
## 17 17 Austin Steeves EAU CLAIRE 2.869565
## 18 18 Brayden Olson LA CROSSE 2.883041
## 19 19 Jace Kirby EAU CLAIRE 2.937500
## 20 20 Aidan Elfering WATERLOO 2.941292
## 21 21 Nick Terhaar DULUTH 3.032051
## 22 22 Will Humphrey THUNDER BAY 3.240000
## 23 23 Jack Mount LA CROSSE 3.312500
## 24 24 Austin Berggren LA CROSSE 3.371901
## 25 25 Rylan Newman THUNDER BAY 3.379147
## 26 26 Sean Waits DULUTH 3.432900
## 27 27 Connor Lovin EAU CLAIRE 3.494505
## 28 28 Patrick Fernandez ROCHESTER 3.500000
## 29 29 Eli Pillsbury WATERLOO 3.547264
## 30 30 Max Arlich EAU CLAIRE 3.600000
## 31 31 Brady Lejeune-Deacutis ROCHESTER 3.602837
## 32 32 Gannon Wentz WATERLOO 3.625000
## 33 33 Kassius Thomas LA CROSSE 3.701754
## 34 34 Kole Bradley WATERLOO 3.718232
## 35 35 Carter Wall THUNDER BAY 3.735931
## 36 36 Tyler Glowacki WATERLOO 3.766284
## 37 37 Josh Glaser EAU CLAIRE 3.781250
## 38 38 Kenneth Fistler EAU CLAIRE 3.818584
## 39 39 Logan Boenker WATERLOO 3.833333
## 40 40 Gaines Estridge ROCHESTER 3.882353
## 41 41 Evan Rolison DULUTH 3.905172
## 42 42 Anthony Andrews DULUTH 3.909091
## 43 43 Beau Alazaus ROCHESTER 3.909091
## 44 44 Caden Richardson LA CROSSE 3.923077
## 45 45 Cristien Banda LA CROSSE 3.947368
## 46 46 Bobby McDonough LA CROSSE 3.989011
## 47 47 Juan Reyes WATERLOO 3.993377
## 48 48 Danny Hesse DULUTH 4.058824
## 49 49 Jackson Kendall DULUTH 4.131579
## 50 50 Walker Retz EAU CLAIRE 4.160131
## 51 51 Andres Castro EAU CLAIRE 4.204188
## 52 52 Jabe Schlehuber THUNDER BAY 4.235294
## 53 53 Troy Benko LA CROSSE 4.255411
## 54 54 Brandon Rice WATERLOO 4.276102
## 55 55 Ryan Higgins ROCHESTER 4.391304
## 56 56 Ian Fisher DULUTH 4.419753
## 57 57 Jimmy Cerha THUNDER BAY 4.428571
## 58 58 Riley Fuller WATERLOO 4.428571
## 59 59 Nathan Vela EAU CLAIRE 4.491713
## 60 60 Jackson Smith DULUTH 4.492147
## 61 61 Ashton Michek LA CROSSE 4.543408
## 62 62 Jacob Tostado ROCHESTER 4.600000
## 63 63 Caden Klebba ROCHESTER 4.631420
## 64 64 Owen Marsolek DULUTH 4.636364
## 65 65 Jaren Ekkelboom ROCHESTER 4.644737
## 66 66 Kai Purdy-Burton WATERLOO 4.688742
## 67 67 Brody Leyboldt WATERLOO 4.698113
## 68 68 Tyler Talbert THUNDER BAY 4.723301
## 69 69 Payton Barton EAU CLAIRE 4.735537
## 70 70 Cameron Johnson THUNDER BAY 4.742739
## 71 71 Christian Galindo ROCHESTER 4.777778
## 72 72 Jack Ghufran LA CROSSE 4.796117
## 73 73 Parker Sweeney WATERLOO 4.800000
## 74 74 Colton Blankstrom WATERLOO 4.809524
## 75 75 Austin Mattingly EAU CLAIRE 4.825397
## 76 76 Chas Melvin IV DULUTH 4.832461
## 77 77 Luke Riggs WATERLOO 4.868132
## 78 78 Ian Regal ROCHESTER 4.906158
## 79 79 Mason Beltrand LA CROSSE 4.956522
## 80 80 Hayden Mullins ROCHESTER 4.968750
## 81 81 Beck Sullivan LA CROSSE 4.987179
## 82 82 Parker Burgess THUNDER BAY 4.987578
## 83 83 Collin Berry THUNDER BAY 5.000000
## 84 84 Luke Elward LA CROSSE 5.000000
## 85 85 Brady Baur WATERLOO 5.000000
## 86 86 Marcus Champagne ROCHESTER 5.047619
## 87 87 Matt Juza DULUTH 5.095238
## 88 88 Easton Bobb EAU CLAIRE 5.145594
## 89 89 Braden Gluth THUNDER BAY 5.176471
## 90 90 Camden Lyke WATERLOO 5.274882
## 91 91 Ethan Froud THUNDER BAY 5.365591
## 92 92 Carter Giesen DULUTH 5.395833
## 93 93 Harrison Cordeiro ROCHESTER 5.500000
## 94 94 Myles Dismute LA CROSSE 5.513089
## 95 95 Alex Alberico WATERLOO 5.561983
## 96 96 Jackson Irwin THUNDER BAY 5.562358
## 97 97 Ethan Minaker THUNDER BAY 5.586207
## 98 98 Bridger Hamilton EAU CLAIRE 5.641509
## 99 99 John McDonald THUNDER BAY 5.733333
## 100 100 Simon Murray DULUTH 5.786070
## 101 101 Isaiah Brennan ROCHESTER 5.882562
## 102 102 William Spang THUNDER BAY 5.900000
## 103 103 Nakni Anna WATERLOO 5.928177
## 104 104 Jace Miner LA CROSSE 5.984293
## 105 105 Dylan Dickert EAU CLAIRE 6.000000
## 106 106 Zach Diver EAU CLAIRE 6.093750
## 107 107 Julian Castro ROCHESTER 6.134328
## 108 108 Matthew Cornelius LA CROSSE 6.313953
## 109 109 Grant Faris THUNDER BAY 6.443709
## 110 110 Nick Bauer ROCHESTER 6.733333
## 111 111 Lorenzo Atwell EAU CLAIRE 6.974359
## 112 112 Harmon Zylstra ROCHESTER 7.166667
## 113 113 James Rheaume DULUTH 7.198895
## 114 114 AJ Rasmussen ROCHESTER 7.210526
## 115 115 Manny Lopez ROCHESTER 7.750000
library(ggplot2)
library(dplyr)
# Rank and divide into performance tiers (lower DICE is better)
GPE_PITCH_FILTERED <- GPE_PITCH_FILTERED %>%
mutate(
DICE_Rank = rank(DICE, ties.method = "first"),
PerformanceTier = case_when(
DICE_Rank <= n() / 3 ~ "Top",
DICE_Rank <= 2 * n() / 3 ~ "Middle",
TRUE ~ "Bottom"
)
)
# Define color palette for tiers
tier_colors <- c("Top" = "green3", "Middle" = "gold", "Bottom" = "red3")
# Scatterplot of DICE vs Batters Faced with labels and color coding
ggplot(GPE_PITCH_FILTERED, aes(x = BF, y = DICE, color = PerformanceTier, label = PLAYER)) +
geom_point(size = 3) +
geom_text(vjust = -0.8, size = 3, check_overlap = TRUE) +
scale_color_manual(values = tier_colors) +
labs(
title = "DICE vs Batters Faced (Color-Coded by Performance Tier)",
x = "Batters Faced (BF)",
y = "DICE (Defense-Independent Component ERA)",
color = "Performance Tier"
) +
theme_minimal(base_size = 14)
#Teams with best/worse DICE
library(dplyr)
# Define thresholds for "low" and "high" DICE based on quantiles
low_threshold <- quantile(GPE_PITCH_FILTERED$DICE, 0.33, na.rm = TRUE)
high_threshold <- quantile(GPE_PITCH_FILTERED$DICE, 0.67, na.rm = TRUE)
# Categorize pitchers by performance tier
GPE_PITCH_FILTERED <- GPE_PITCH_FILTERED %>%
mutate(DICE_Tier = case_when(
DICE <= low_threshold ~ "Low DICE (Good)",
DICE >= high_threshold ~ "High DICE (Poor)",
TRUE ~ "Mid DICE"
))
# Count number of low/high DICE pitchers per team
Team_DICE_Tiers <- GPE_PITCH_FILTERED %>%
group_by(TEAM, DICE_Tier) %>%
summarise(Count = n(), .groups = "drop")
# Teams with most low DICE pitchers
Top_Low_DICE_Teams <- Team_DICE_Tiers %>%
filter(DICE_Tier == "Low DICE (Good)") %>%
arrange(desc(Count))
# Teams with most high DICE pitchers
Top_High_DICE_Teams <- Team_DICE_Tiers %>%
filter(DICE_Tier == "High DICE (Poor)") %>%
arrange(desc(Count))
# Print results
cat("Teams with Most Low-DICE Pitchers (Best Performers):\n")
## Teams with Most Low-DICE Pitchers (Best Performers):
print(Top_Low_DICE_Teams)
## # A tibble: 6 × 3
## TEAM DICE_Tier Count
## <chr> <chr> <int>
## 1 EAU CLAIRE Low DICE (Good) 9
## 2 LA CROSSE Low DICE (Good) 9
## 3 DULUTH Low DICE (Good) 6
## 4 WATERLOO Low DICE (Good) 6
## 5 ROCHESTER Low DICE (Good) 4
## 6 THUNDER BAY Low DICE (Good) 4
cat("\nTeams with Most High-DICE Pitchers (Worst Performers):\n")
##
## Teams with Most High-DICE Pitchers (Worst Performers):
print(Top_High_DICE_Teams)
## # A tibble: 6 × 3
## TEAM DICE_Tier Count
## <chr> <chr> <int>
## 1 ROCHESTER High DICE (Poor) 10
## 2 THUNDER BAY High DICE (Poor) 9
## 3 LA CROSSE High DICE (Poor) 6
## 4 EAU CLAIRE High DICE (Poor) 5
## 5 DULUTH High DICE (Poor) 4
## 6 WATERLOO High DICE (Poor) 4
# Define new weights (sum ≈ 1)
weights_pitching_v2 <- c(
ERA = -0.15,
WHIP = -0.20,
K.9 = 0.10,
BB = -0.05,
H = -0.05,
FPS. = 0.05,
IP = 0.10,
BAA = -0.10,
DICE = -0.40 # heavily weighted (lower DICE is better)
)
GPE_PITCH_FILTERED <- GPE_PITCH_FILTERED %>%
mutate(
PitchingScore_v2 = (
ERA * weights_pitching_v2["ERA"] +
WHIP * weights_pitching_v2["WHIP"] +
K.9 * weights_pitching_v2["K.9"] +
BB * weights_pitching_v2["BB"] +
H * weights_pitching_v2["H"] +
FPS. * weights_pitching_v2["FPS."] +
IP * weights_pitching_v2["IP"] +
BAA * weights_pitching_v2["BAA"] +
DICE * weights_pitching_v2["DICE"]
)
)
GPE_PITCH_FILTERED %>%
arrange(desc(PitchingScore_v2)) %>%
select(PLAYER, TEAM, PitchingScore_v2)
## PLAYER TEAM PitchingScore_v2
## 1 Dawson Hargrove EAU CLAIRE 5.04264143
## 2 Zack Serup ROCHESTER 4.56510443
## 3 Cohen Gomez EAU CLAIRE 4.12213527
## 4 Chris Petersen WATERLOO 3.68067671
## 5 Nate Vidlak DULUTH 3.59240000
## 6 Aidan Elfering WATERLOO 3.52768337
## 7 Maddox Meyer DULUTH 3.48048276
## 8 Jack Mount LA CROSSE 3.30500000
## 9 Makaio Cisneros THUNDER BAY 3.07821538
## 10 Luispablo Navarro LA CROSSE 2.96460199
## 11 Parker Thomas DULUTH 2.91488182
## 12 Tanner Foertsch DULUTH 2.86683422
## 13 Beau Alazaus ROCHESTER 2.86396364
## 14 Nick Terhaar DULUTH 2.85697949
## 15 Walker Retz EAU CLAIRE 2.80134771
## 16 Aaron England LA CROSSE 2.77483908
## 17 Miller Green EAU CLAIRE 2.71113665
## 18 Caden Richardson LA CROSSE 2.70916923
## 19 Sean Waits DULUTH 2.61173983
## 20 Jace Kirby EAU CLAIRE 2.60880000
## 21 Josh Glaser EAU CLAIRE 2.58460000
## 22 Tyler Glowacki WATERLOO 2.48278659
## 23 Brady Lejeune-Deacutis ROCHESTER 2.47906525
## 24 Tyler Gebb LA CROSSE 2.41992857
## 25 Max Arlich EAU CLAIRE 2.41470000
## 26 Kenneth Fistler EAU CLAIRE 2.18866637
## 27 Mateo Gray LA CROSSE 2.16179078
## 28 Will Humphrey THUNDER BAY 2.15990000
## 29 Ashton Michek LA CROSSE 2.11393666
## 30 Brandon Rice WATERLOO 2.10465916
## 31 Gaines Estridge ROCHESTER 2.07995882
## 32 Evan Rolison DULUTH 1.99213103
## 33 Gannon Wentz WATERLOO 1.98920000
## 34 Kole Bradley WATERLOO 1.96900718
## 35 Austin Berggren LA CROSSE 1.95483967
## 36 Carter Wall THUNDER BAY 1.90602771
## 37 Braden Gluth THUNDER BAY 1.90431176
## 38 Austin Steeves EAU CLAIRE 1.86097391
## 39 Anthony Andrews DULUTH 1.85846364
## 40 Bobby McDonough LA CROSSE 1.85619560
## 41 Jake Jakubowski LA CROSSE 1.83310000
## 42 Brayden Olson LA CROSSE 1.83248363
## 43 Rylan Newman THUNDER BAY 1.82624123
## 44 Jackson Kendall DULUTH 1.78206842
## 45 Mason Beltrand LA CROSSE 1.77679130
## 46 Kassius Thomas LA CROSSE 1.65869825
## 47 Caden Klebba ROCHESTER 1.61893202
## 48 Ian Regal ROCHESTER 1.59383666
## 49 Eli Pillsbury WATERLOO 1.57259453
## 50 Hayden Mullins ROCHESTER 1.57050000
## 51 Andres Castro EAU CLAIRE 1.56862461
## 52 Jack Ghufran LA CROSSE 1.55125340
## 53 Logan Boenker WATERLOO 1.46706667
## 54 Payton Barton EAU CLAIRE 1.44598512
## 55 Jackson Smith DULUTH 1.42564136
## 56 Christian Galindo ROCHESTER 1.41298889
## 57 Cristien Banda LA CROSSE 1.32685263
## 58 Danny Hesse DULUTH 1.31247059
## 59 Diego Luzardo ROCHESTER 1.23574106
## 60 Ian Fisher DULUTH 1.22209877
## 61 Riley Fuller WATERLOO 1.19767143
## 62 Parker Sweeney WATERLOO 1.05870000
## 63 Myles Dismute LA CROSSE 1.02936440
## 64 Juan Reyes WATERLOO 0.94164901
## 65 Patrick Fernandez ROCHESTER 0.91700000
## 66 Brody Leyboldt WATERLOO 0.91495472
## 67 Nathan Vela EAU CLAIRE 0.88021492
## 68 Jabe Schlehuber THUNDER BAY 0.84838235
## 69 Tyler Talbert THUNDER BAY 0.84467961
## 70 Owen Marsolek DULUTH 0.76455455
## 71 Cameron Johnson THUNDER BAY 0.67690456
## 72 Ryan Higgins ROCHESTER 0.66517826
## 73 Troy Benko LA CROSSE 0.60163550
## 74 Brady Baur WATERLOO 0.56520000
## 75 Jacob Tostado ROCHESTER 0.55340000
## 76 Connor Lovin EAU CLAIRE 0.54299780
## 77 Austin Mattingly EAU CLAIRE 0.52334127
## 78 Carter Giesen DULUTH 0.50326667
## 79 Parker Burgess THUNDER BAY 0.37876894
## 80 Easton Bobb EAU CLAIRE 0.36846245
## 81 Luke Elward LA CROSSE 0.28960000
## 82 Colton Blankstrom WATERLOO 0.13779048
## 83 Chas Melvin IV DULUTH 0.11411571
## 84 Dylan Dickert EAU CLAIRE 0.10940000
## 85 Jaren Ekkelboom ROCHESTER 0.01980526
## 86 Jimmy Cerha THUNDER BAY -0.03422857
## 87 Jackson Irwin THUNDER BAY -0.03664331
## 88 Ethan Froud THUNDER BAY -0.04293656
## 89 Ethan Minaker THUNDER BAY -0.07698276
## 90 Marcus Champagne ROCHESTER -0.09554762
## 91 Collin Berry THUNDER BAY -0.14920000
## 92 Simon Murray DULUTH -0.27132786
## 93 Camden Lyke WATERLOO -0.27895261
## 94 Kai Purdy-Burton WATERLOO -0.32469669
## 95 Julian Castro ROCHESTER -0.42523134
## 96 Luke Riggs WATERLOO -0.44745275
## 97 Zach Diver EAU CLAIRE -0.51190000
## 98 Matt Juza DULUTH -0.54409524
## 99 Alex Alberico WATERLOO -0.57839339
## 100 Harrison Cordeiro ROCHESTER -0.58000000
## 101 Matthew Cornelius LA CROSSE -0.63618140
## 102 John McDonald THUNDER BAY -0.64133333
## 103 Bridger Hamilton EAU CLAIRE -0.83970377
## 104 Beck Sullivan LA CROSSE -1.07747179
## 105 William Spang THUNDER BAY -1.19250000
## 106 Harmon Zylstra ROCHESTER -1.20426667
## 107 James Rheaume DULUTH -1.38405801
## 108 Isaiah Brennan ROCHESTER -1.43462491
## 109 Nakni Anna WATERLOO -1.54247072
## 110 Nick Bauer ROCHESTER -1.65503333
## 111 AJ Rasmussen ROCHESTER -1.69421053
## 112 Jace Miner LA CROSSE -1.90851728
## 113 Lorenzo Atwell EAU CLAIRE -2.07524359
## 114 Manny Lopez ROCHESTER -2.45750000
## 115 Grant Faris THUNDER BAY -2.51028344
#plot with names
ggplot(GPE_PITCH_FILTERED, aes(x = IP, y = PitchingScore_v2, color = PitchingScore_v2)) +
geom_point() +
geom_text(aes(label = PLAYER), vjust = -0.5, size = 3) +
scale_color_gradient(low = "red", high = "green") +
labs(title = "Pitching Score v2 vs Innings Pitched", x = "Innings Pitched", y = "Pitching Score v2") +
theme_minimal()
library(ggplot2)
library(plotly)
##
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
#Hover plot
# Create tooltip column
GPE_PITCH_FILTERED <- GPE_PITCH_FILTERED %>%
mutate(tooltip = paste(
"Player:", PLAYER,
"<br>Team:", TEAM,
"<br>Score:", round(PitchingScore_v2, 2)
))
# Fit regression model
fit <- lm(PitchingScore_v2 ~ IP, data = GPE_PITCH_FILTERED)
# Create regression line data
line_data <- data.frame(
IP = seq(
min(GPE_PITCH_FILTERED$IP, na.rm = TRUE),
max(GPE_PITCH_FILTERED$IP, na.rm = TRUE),
length.out = 100
)
)
line_data$pred <- predict(fit, newdata = line_data)
# ✅ Build ggplot (explicitly define text inside geom_point())
p <- ggplot(GPE_PITCH_FILTERED, aes(x = IP, y = PitchingScore_v2, color = PitchingScore_v2)) +
geom_point(aes(text = tooltip), size = 3) + # ✅ tooltip defined here
geom_line(data = line_data, aes(x = IP, y = pred),
color = "black", linetype = "dashed", linewidth = 1) +
scale_color_gradient(low = "red", high = "green") +
labs(
title = "Pitching Score v2 vs Innings Pitched",
x = "Innings Pitched",
y = "Pitching Score v2"
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, face = "bold"),
legend.position = "right"
)
## Warning in geom_point(aes(text = tooltip), size = 3): Ignoring unknown
## aesthetics: text
# ✅ Convert to interactive Plotly chart
ggplotly(p, tooltip = "text")
mean(GPE_PITCH_FILTERED$PitchingScore_v2, na.rm = TRUE)
## [1] 1.107737
library(ggplot2)
library(plotly)
library(dplyr)
# --- 1. Scale PitchingScore_v2 like ERA+ (league average = 100) ---
league_avg <- mean(GPE_PITCH_FILTERED$PitchingScore_v2, na.rm = TRUE)
GPE_PITCH_FILTERED <- GPE_PITCH_FILTERED %>%
mutate(
PitchingScore_v2_100 = 100 * (PitchingScore_v2 / league_avg),
tooltip = paste(
"Player:", PLAYER,
"<br>Team:", TEAM,
"<br>Score:", round(PitchingScore_v2_100, 1)
)
)
# --- 2. Fit regression model for trend line ---
fit <- lm(PitchingScore_v2_100 ~ IP, data = GPE_PITCH_FILTERED)
line_data <- data.frame(
IP = seq(
min(GPE_PITCH_FILTERED$IP, na.rm = TRUE),
max(GPE_PITCH_FILTERED$IP, na.rm = TRUE),
length.out = 100
)
)
line_data$pred <- predict(fit, newdata = line_data)
# --- 3. Build ggplot with custom team colors ---
p_pitch <- ggplot(GPE_PITCH_FILTERED, aes(x = IP, y = PitchingScore_v2_100, color = TEAM)) +
geom_point(aes(text = tooltip), size = 3) +
geom_line(data = line_data, aes(x = IP, y = pred),
color = "black", linetype = "dashed", linewidth = 1) +
scale_color_manual(
values = c(
"DULUTH" = "blue",
"EAU CLAIRE" = "orange",
"THUNDER BAY" = "red",
"LA CROSSE" = "green",
"ROCHESTER" = "purple",
"WATERLOO" = "yellow"
)
) +
labs(
title = "Pitching Score v2 vs Innings Pitched (League Avg = 100)",
x = "Innings Pitched",
y = "Pitching Score v2 (Scaled)",
color = "Team"
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, face = "bold"),
legend.position = "right"
)
## Warning in geom_point(aes(text = tooltip), size = 3): Ignoring unknown
## aesthetics: text
# --- 4. Convert to interactive Plotly chart ---
ggplotly(p_pitch, tooltip = "text")
summary(fit)
##
## Call:
## lm(formula = PitchingScore_v2_100 ~ IP, data = GPE_PITCH_FILTERED)
##
## Residuals:
## Min 1Q Median 3Q Max
## -343.71 -86.82 11.46 88.54 358.16
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.575 38.194 -0.041 0.96717
## IP 3.930 1.395 2.817 0.00572 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 135.2 on 113 degrees of freedom
## Multiple R-squared: 0.06563, Adjusted R-squared: 0.05737
## F-statistic: 7.938 on 1 and 113 DF, p-value: 0.005716
library(plotly)
# --- 1. Extract regression info from your model ---
intercept <- coef(fit)[1]
slope <- coef(fit)[2]
r2 <- summary(fit)$r.squared
pval <- summary(fit)$coefficients[2, 4]
# --- 2. Create formatted annotation text ---
eq_text <- paste0(
"y = ", round(intercept, 3), " + ", round(slope, 3), "x",
"<br>R² = ", round(r2, 3),
"<br>p = ", format(pval, scientific = TRUE, digits = 3)
)
# --- 3. Convert ggplot to Plotly and add annotation ---
p_pitch_plotly <- ggplotly(p_pitch, tooltip = "text") %>%
layout(
annotations = list(
x = 0.98, y = 0.98, # top-right corner (0-1 in "paper" coordinates)
xref = "paper", yref = "paper",
text = eq_text,
showarrow = FALSE,
align = "right",
font = list(size = 12, color = "black")
)
)
# --- 4. Display interactive plot ---
p_pitch_plotly
library(dplyr)
# --- Scale PitchingScore_v2 similar to OPS+ (league avg = 100) ---
GPE_PITCH_FILTERED <- GPE_PITCH_FILTERED %>%
mutate(
PitchingScore_v2_100 = 100 + 15 * ((PitchingScore_v2 - mean(PitchingScore_v2, na.rm = TRUE)) /
sd(PitchingScore_v2, na.rm = TRUE))
)
# --- Create full pitching leaderboard ---
pitching_leaderboard <- GPE_PITCH_FILTERED %>%
select(PLAYER, TEAM, IP, PitchingScore_v2_100) %>%
arrange(desc(PitchingScore_v2_100)) %>%
mutate(Rank = row_number())
# --- Print the full leaderboard ---
print(pitching_leaderboard)
## PLAYER TEAM IP PitchingScore_v2_100 Rank
## 1 Dawson Hargrove EAU CLAIRE 25.1 138.26417 1
## 2 Zack Serup ROCHESTER 27.1 133.62046 2
## 3 Cohen Gomez EAU CLAIRE 48.2 129.31290 3
## 4 Chris Petersen WATERLOO 29.2 125.02002 4
## 5 Nate Vidlak DULUTH 20.0 124.16159 5
## 6 Aidan Elfering WATERLOO 51.1 123.53227 6
## 7 Maddox Meyer DULUTH 23.2 123.07328 7
## 8 Jack Mount LA CROSSE 16.0 121.36683 8
## 9 Makaio Cisneros THUNDER BAY 26.0 119.16151 9
## 10 Luispablo Navarro LA CROSSE 20.1 118.05670 10
## 11 Parker Thomas DULUTH 22.0 117.57321 11
## 12 Tanner Foertsch DULUTH 30.1 117.10598 12
## 13 Beau Alazaus ROCHESTER 57.2 117.07806 13
## 14 Nick Terhaar DULUTH 31.2 117.01015 14
## 15 Walker Retz EAU CLAIRE 61.2 116.46917 15
## 16 Aaron England LA CROSSE 26.1 116.21139 16
## 17 Miller Green EAU CLAIRE 16.1 115.59193 17
## 18 Caden Richardson LA CROSSE 39.0 115.57280 18
## 19 Sean Waits DULUTH 23.1 114.62536 19
## 20 Jace Kirby EAU CLAIRE 16.0 114.59678 20
## 21 Josh Glaser EAU CLAIRE 19.2 114.36145 21
## 22 Tyler Glowacki WATERLOO 26.1 113.37139 22
## 23 Brady Lejeune-Deacutis ROCHESTER 28.2 113.33520 23
## 24 Tyler Gebb LA CROSSE 28.0 112.76014 24
## 25 Max Arlich EAU CLAIRE 30.0 112.70929 25
## 26 Kenneth Fistler EAU CLAIRE 45.2 110.51127 26
## 27 Mateo Gray LA CROSSE 28.2 110.24993 27
## 28 Will Humphrey THUNDER BAY 25.0 110.23154 28
## 29 Ashton Michek LA CROSSE 31.1 109.78458 29
## 30 Brandon Rice WATERLOO 43.1 109.69436 30
## 31 Gaines Estridge ROCHESTER 17.0 109.45417 31
## 32 Evan Rolison DULUTH 23.2 108.60011 32
## 33 Gannon Wentz WATERLOO 24.0 108.57160 33
## 34 Kole Bradley WATERLOO 18.1 108.37524 34
## 35 Austin Berggren LA CROSSE 24.2 108.23747 35
## 36 Carter Wall THUNDER BAY 23.1 107.76281 36
## 37 Braden Gluth THUNDER BAY 34.0 107.74613 37
## 38 Austin Steeves EAU CLAIRE 23.0 107.32470 38
## 39 Anthony Andrews DULUTH 22.0 107.30028 39
## 40 Bobby McDonough LA CROSSE 18.2 107.27823 40
## 41 Jake Jakubowski LA CROSSE 22.0 107.05364 41
## 42 Brayden Olson LA CROSSE 17.1 107.04765 42
## 43 Rylan Newman THUNDER BAY 21.1 106.98694 43
## 44 Jackson Kendall DULUTH 38.0 106.55739 44
## 45 Mason Beltrand LA CROSSE 32.2 106.50608 45
## 46 Kassius Thomas LA CROSSE 17.1 105.35771 46
## 47 Caden Klebba ROCHESTER 33.1 104.97101 47
## 48 Ian Regal ROCHESTER 34.1 104.72697 48
## 49 Eli Pillsbury WATERLOO 40.2 104.52041 49
## 50 Hayden Mullins ROCHESTER 32.0 104.50004 50
## 51 Andres Castro EAU CLAIRE 19.1 104.48180 51
## 52 Jack Ghufran LA CROSSE 41.2 104.31288 52
## 53 Logan Boenker WATERLOO 30.0 103.49422 53
## 54 Payton Barton EAU CLAIRE 24.2 103.28922 54
## 55 Jackson Smith DULUTH 38.2 103.09139 55
## 56 Christian Galindo ROCHESTER 18.0 102.96836 56
## 57 Cristien Banda LA CROSSE 38.0 102.13074 57
## 58 Danny Hesse DULUTH 34.0 101.99089 58
## 59 Diego Luzardo ROCHESTER 15.1 101.24475 59
## 60 Ian Fisher DULUTH 16.2 101.11208 60
## 61 Riley Fuller WATERLOO 28.0 100.87455 61
## 62 Parker Sweeney WATERLOO 25.0 99.52315 62
## 63 Myles Dismute LA CROSSE 19.1 99.23788 63
## 64 Juan Reyes WATERLOO 15.1 98.38491 64
## 65 Patrick Fernandez ROCHESTER 18.0 98.14521 65
## 66 Brody Leyboldt WATERLOO 21.2 98.12532 66
## 67 Nathan Vela EAU CLAIRE 18.1 97.78750 67
## 68 Jabe Schlehuber THUNDER BAY 17.0 97.47796 68
## 69 Tyler Talbert THUNDER BAY 41.2 97.44195 69
## 70 Owen Marsolek DULUTH 22.0 96.66279 70
## 71 Cameron Johnson THUNDER BAY 24.1 95.81045 71
## 72 Ryan Higgins ROCHESTER 23.0 95.69642 72
## 73 Troy Benko LA CROSSE 23.1 95.07852 73
## 74 Brady Baur WATERLOO 31.0 94.72421 74
## 75 Jacob Tostado ROCHESTER 20.0 94.60946 75
## 76 Connor Lovin EAU CLAIRE 18.2 94.50831 76
## 77 Austin Mattingly EAU CLAIRE 25.2 94.31716 77
## 78 Carter Giesen DULUTH 19.2 94.12195 78
## 79 Parker Burgess THUNDER BAY 16.1 92.91130 79
## 80 Easton Bobb EAU CLAIRE 26.1 92.81107 80
## 81 Luke Elward LA CROSSE 16.0 92.04419 81
## 82 Colton Blankstrom WATERLOO 21.0 90.56795 82
## 83 Chas Melvin IV DULUTH 19.1 90.33773 83
## 84 Dylan Dickert EAU CLAIRE 19.0 90.29187 84
## 85 Jaren Ekkelboom ROCHESTER 15.2 89.42063 85
## 86 Jimmy Cerha THUNDER BAY 23.1 88.89519 86
## 87 Jackson Irwin THUNDER BAY 44.1 88.87170 87
## 88 Ethan Froud THUNDER BAY 37.2 88.81051 88
## 89 Ethan Minaker THUNDER BAY 29.0 88.47943 89
## 90 Marcus Champagne ROCHESTER 21.0 88.29890 90
## 91 Collin Berry THUNDER BAY 17.0 87.77717 91
## 92 Simon Murray DULUTH 20.1 86.58956 92
## 93 Camden Lyke WATERLOO 21.1 86.51542 93
## 94 Kai Purdy-Burton WATERLOO 30.2 86.07059 94
## 95 Julian Castro ROCHESTER 20.1 85.09296 95
## 96 Luke Riggs WATERLOO 18.2 84.87687 96
## 97 Zach Diver EAU CLAIRE 32.0 84.25017 97
## 98 Matt Juza DULUTH 21.0 83.93709 98
## 99 Alex Alberico WATERLOO 24.2 83.60357 99
## 100 Harrison Cordeiro ROCHESTER 24.0 83.58794 100
## 101 Matthew Cornelius LA CROSSE 17.2 83.04162 101
## 102 John McDonald THUNDER BAY 30.0 82.99152 102
## 103 Bridger Hamilton EAU CLAIRE 21.2 81.06251 103
## 104 Beck Sullivan LA CROSSE 31.2 78.75038 104
## 105 William Spang THUNDER BAY 20.0 77.63181 105
## 106 Harmon Zylstra ROCHESTER 18.0 77.51739 106
## 107 James Rheaume DULUTH 18.1 75.76905 107
## 108 Isaiah Brennan ROCHESTER 28.1 75.27732 108
## 109 Nakni Anna WATERLOO 18.1 74.22859 109
## 110 Nick Bauer ROCHESTER 30.0 73.13400 110
## 111 AJ Rasmussen ROCHESTER 17.1 72.75303 111
## 112 Jace Miner LA CROSSE 19.1 70.66905 112
## 113 Lorenzo Atwell EAU CLAIRE 31.2 69.04775 113
## 114 Manny Lopez ROCHESTER 20.0 65.33058 114
## 115 Grant Faris THUNDER BAY 30.2 64.81730 115
print(GPE_PITCH_FILTERED$PitchingScore_v2_OPAplus)
## NULL
print(GPE_PITCH_FILTERED$PitchingScore_v2_100)
## [1] 112.70929 69.04775 103.28922 92.81107 104.48180 90.29187 84.25017
## [8] 110.51127 114.36145 129.31290 115.59193 81.06251 138.26417 114.59678
## [15] 94.50831 94.31716 116.46917 107.32470 97.78750 107.30028 101.11208
## [22] 117.10598 94.12195 101.99089 83.93709 106.55739 96.66279 90.33773
## [29] 123.07328 86.58956 75.76905 108.60011 103.09139 117.01015 117.57321
## [36] 124.16159 114.62536 87.77717 92.91130 88.89519 119.16151 64.81730
## [43] 88.81051 107.74613 110.23154 88.87170 95.81045 82.99152 88.47943
## [50] 106.98694 97.47796 77.63181 97.44195 107.76281 102.13074 106.50608
## [57] 95.07852 108.23747 83.04162 99.23788 92.04419 116.21139 112.76014
## [64] 104.31288 110.24993 107.05364 107.27823 109.78458 70.66905 121.36683
## [71] 118.05670 107.04765 115.57280 78.75038 105.35771 117.07806 73.13400
## [78] 75.27732 85.09296 88.29890 83.58794 89.42063 109.45417 98.14521
## [85] 102.96836 95.69642 104.97101 113.33520 65.33058 101.24475 104.50004
## [92] 72.75303 104.72697 133.62046 94.60946 77.51739 83.60357 74.22859
## [99] 94.72421 90.56795 103.49422 108.37524 123.53227 100.87455 113.37139
## [106] 98.12532 86.51542 125.02002 104.52041 86.07059 98.38491 109.69436
## [113] 84.87687 99.52315 108.57160
```{Top/Bottom 25} library(dplyr)
top_25 <- GPE_PITCH_FILTERED %>% arrange(desc(PitchingScore_v2)) %>% slice_head(n = 25) %>% select(PLAYER, TEAM, PitchingScore_v2)
bottom_25 <- GPE_PITCH_FILTERED %>% arrange(PitchingScore_v2) %>% slice_head(n = 25) %>% select(PLAYER, TEAM, PitchingScore_v2)
top_25 bottom_25
```